#ifndef multimatrix_h
#define multimatrix_h

/** ===================================
   Usage: place this file in the RGBMatrix directory.
		  It should be in the same directory as RGBMatrix.h.
		  I placed it directly in our repo to make our lives easier with version control.
 
		  If you think that you've pulled changes to this code from the repository, 
	      but you aren't seeing any difference, make sure that you've copy/pasted to the RGBMatrix directory.
  =================================== */

#include "RGBMatrix.h"

// the board's (0, 0) LED is in the top left
const unsigned int NORTH = 10;

// the board's (0, 0) LED is in the bottom right
const unsigned int SOUTH = NORTH + 10;

// count of rows available when the matrices are arranged in a big square
const unsigned int MULTI_NUM_ROWS = NUM_ROWS * 2;

// count of columns available when the matrices are arranged in a big square
const unsigned int MULTI_NUM_COLUMNS = NUM_COLUMNS * 2;

/**
 * Manages four matrices that are placed together to form a single big square.
 * Allows the programmer to treat them as a single large LED matrix.
 *
 * Some commands, like fillChar() or scroll(), are not implemented.
 * Translating the bitmaps to fill the entire screen seemed like an unnecessary effort.
 * However, aside from that, it should not be necessary to use RGBMatrix directly,
 * if you're trying to do a pattern across the entire big square.
 *
 * Use the library through the singleton instance: `MultiMatrix`.
 *
 * Note that the fill*() calls won't do anything until MultiMatrix.display() is called.
 *
 * The semantics of the methods other than begin() are the same as for RGBMatrix,
 * except the methods apply to the big square instead of an individual screen. Just look in the documentation there.
 */
class cMultiMatrix
{
public:

	/**
	 * Initializes the MultiMatrix and RGBMatrix. (Calling RGBMatrix.begin() is neither necessary nor advisable.)
	 *
	 * Args:
	 *		topLeftBoardIndex	the daisy chain index of the top left board in the square
	 *		topLeftFacing		the direction of the top left board (NORTH or SOUTH)
	 *
	 *		topRightBoardIndex	the daisy chain index of the top right board in the square
	 *		topRightFacing		the direction of the top right board (NORTH or SOUTH)
	 *
	 *		bottomRightBoardIndex	the daisy chain index of the bottom right board in the square
	 *		bottomRightFacing		the direction of the bottom right board (NORTH or SOUTH)
	 *
	 *		bottomLeftBoardIndex	the daisy chain index of the bottom left board in the square
	 *		bottomLeftFacing		the direction of the bottom left board (NORTH or SOUTH)
	 *
	 * Example configuration: https://docs.google.com/drawings/d/1EOwtH6-t2ohUomp0dJo6Py3g9ws6nvQaNZmR3QT7bkc/edit?hl=en&pli=1
	 *
	 * Note that with daisy-chained LEDs, 0 is the one furthest away from the master:
	 *
	 *		Arduino -> LED3 -> LED2 -> LED1 -> LED0
	 *
	 */
	void begin(const unsigned int topLeftBoardIndex, const unsigned int topLeftFacing,
		const unsigned int topRightBoardIndex, const unsigned int topRightFacing,
		const unsigned int bottomRightBoardIndex, const unsigned int bottomRightFacing,
		const unsigned int bottomLeftBoardIndex, const unsigned int bottomLeftFacing);

	char fillPixel(int row, int column, char color);

	char fillColumn(int column, char color);

	char fillRow(int row, char color);

	char fillScreen(char color);

	void display(void);

	void clear(void);

private:
	unsigned int _topLeftBoardIndex, _topRightBoardIndex, _bottomRightBoardIndex, _bottomLeftBoardIndex;
	unsigned int _topLeftFacing, _topRightFacing, _bottomRightFacing, _bottomLeftFacing;

	// maintains data about a pixel in the matrix collection
	struct PixelData
	{
		const unsigned int screenIndex;
		const unsigned int rowIndex;
		const unsigned int columnIndex;
	};

	/**
	 * Get the RGBMatrix coodinate for the specified MultiMatrix coordinates (rowIndex, columnIndex)
	 *
	 * Example: rowIndex = 10, columnIndex = 10
	 * Return: {screenIndex = 1, rowIndex = 2, columnIndex = 2}
	 *
	 * This allows you to work with the RGBMatrix API. (See cMultiMatrix::fillPixel() for an example of how this is done.)	
	 */ 
	PixelData _getPixelDataForCoords(const unsigned int rowIndex, const unsigned int columnIndex);

	PixelData _getScreenForCoords(const unsigned int rowIndex, const unsigned int columnIndex);
};

extern cMultiMatrix MultiMatrix;

#endif